from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form
from sqlalchemy.orm import Session
from typing import List, Optional
import os
import json

from app.database import get_db
from app.api.auth import get_current_user
from app.db_models.user import User
from app.db_models.prediction_log import PredictionLog
from app.schemas.detection import (
    Algorithm, AlgorithmCreate,
    Dataset, DatasetCreate,
    Task, TaskCreate,
    Result, ResultCreate,
    TaskDetailResponse, TaskStatistics
)
from app.schemas.response import Response, ResponseCode
from app.api.detection import (
    get_algorithms, get_algorithm, create_algorithm,
    get_datasets, get_dataset, create_dataset,
    process_dataset, save_uploaded_file,
    create_detection_task, get_tasks, get_task,
    get_task_detail, start_detection, get_task_statistics
)
from app.api.ml_interface import get_available_models, run_prediction, get_latest_prediction_result, save_prediction_to_db

# 创建路由器
router = APIRouter(
    prefix="/detection",
    tags=["detection"],
    responses={404: {"description": "Not found"}},
)

# 定义上传文件保存目录
UPLOAD_DIR = "uploads/datasets"


@router.get("/algorithms", response_model=Response[List[Algorithm]])
def read_algorithms(db: Session = Depends(get_db)):
    """获取所有可用算法
    
    Returns:
        Response[List[Algorithm]]: 算法列表
    """
    algorithms = get_algorithms(db)
    return Response.success(data=algorithms, message="获取算法列表成功")


@router.get("/algorithms/{algorithm_id}", response_model=Response[Algorithm])
def read_algorithm(algorithm_id: int, db: Session = Depends(get_db)):
    """获取单个算法详情
    
    Args:
        algorithm_id: 算法ID
        
    Returns:
        Response[Algorithm]: 算法详情
    """
    algorithm = get_algorithm(db, algorithm_id)
    if not algorithm:
        return Response.fail(
            code=ResponseCode.NOT_FOUND,
            message="算法不存在"
        )
    return Response.success(data=algorithm, message="获取算法详情成功")


@router.post("/datasets/upload", response_model=Response[Dataset])
def upload_dataset(
    file: UploadFile = File(...),
    name: str = Form(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """上传数据集文件
    
    Args:
        file: 上传的数据集文件
        name: 数据集名称
        
    Returns:
        Response[Dataset]: 创建的数据集信息
    """
    try:
        # 保存上传文件
        filepath = save_uploaded_file(file, UPLOAD_DIR)
        
        # 处理数据集，提取特征
        data_count, feature_count, class_count = process_dataset(filepath)
        
        # 创建数据集记录
        dataset_data = DatasetCreate(
            name=name,
            file_path=filepath,
            record_count=data_count,
            feature_count=feature_count,
            class_count=class_count
        )
        dataset = create_dataset(db, dataset_data, current_user.id)
        
        return Response.success(data=dataset, message="数据集上传成功")
    except Exception as e:
        return Response.error(message=f"数据集上传失败: {str(e)}")


@router.get("/datasets", response_model=Response[List[Dataset]])
def read_datasets(
    skip: int = 0,
    limit: int = 100,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """获取数据集列表
    
    Args:
        skip: 跳过记录数
        limit: 返回记录数
        
    Returns:
        Response[List[Dataset]]: 数据集列表
    """
    datasets = get_datasets(db, skip, limit)
    return Response.success(data=datasets, message="获取数据集列表成功")


@router.get("/datasets/{dataset_id}", response_model=Response[Dataset])
def read_dataset(
    dataset_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """获取单个数据集详情
    
    Args:
        dataset_id: 数据集ID
        
    Returns:
        Response[Dataset]: 数据集详情
    """
    dataset = get_dataset(db, dataset_id)
    if not dataset:
        return Response.fail(
            code=ResponseCode.NOT_FOUND,
            message="数据集不存在"
        )
    return Response.success(data=dataset, message="获取数据集详情成功")


@router.post("/tasks", response_model=Response[Task])
def create_task(
    task: TaskCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """创建检测任务
    
    Args:
        task: 任务创建数据
        
    Returns:
        Response[Task]: 创建的任务
    """
    try:
        # 检查算法是否存在
        algorithm = get_algorithm(db, task.algorithm_id)
        if not algorithm:
            return Response.fail(
                code=ResponseCode.BAD_REQUEST,
                message="选择的算法不存在"
            )
        
        # 检查数据集是否存在
        dataset = get_dataset(db, task.dataset_id)
        if not dataset:
            return Response.fail(
                code=ResponseCode.BAD_REQUEST,
                message="选择的数据集不存在"
            )
        
        # 创建任务
        detection_task = create_detection_task(db, task, current_user.id)
        
        return Response.success(data=detection_task, message="检测任务创建成功")
    except Exception as e:
        return Response.error(message=f"创建检测任务失败: {str(e)}")


@router.get("/tasks", response_model=Response[List[Task]])
def read_tasks(
    skip: int = 0,
    limit: int = 100,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """获取当前用户的检测任务列表
    
    Args:
        skip: 跳过记录数
        limit: 返回记录数
        
    Returns:
        Response[List[Task]]: 任务列表
    """
    tasks = get_tasks(db, current_user.id, skip, limit)
    return Response.success(data=tasks, message="获取任务列表成功")


@router.get("/tasks/{task_id}", response_model=Response[TaskDetailResponse])
def read_task(
    task_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """获取单个任务详情
    
    Args:
        task_id: 任务ID
        
    Returns:
        Response[TaskDetailResponse]: 任务详情
    """
    task_detail = get_task_detail(db, task_id)
    if not task_detail:
        return Response.fail(
            code=ResponseCode.NOT_FOUND,
            message="任务不存在"
        )
    
    # 检查是否为当前用户的任务
    if task_detail.task.user_id != current_user.id:
        return Response.fail(
            code=ResponseCode.FORBIDDEN,
            message="无权访问此任务"
        )
    
    return Response.success(data=task_detail, message="获取任务详情成功")


@router.post("/tasks/{task_id}/start", response_model=Response[Task])
def start_task(
    task_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """开始执行检测任务
    
    Args:
        task_id: 任务ID
        
    Returns:
        Response[Task]: 更新后的任务
    """
    # 检查任务是否存在
    task = get_task(db, task_id)
    if not task:
        return Response.fail(
            code=ResponseCode.NOT_FOUND,
            message="任务不存在"
        )
    
    # 检查是否为当前用户的任务
    if task.user_id != current_user.id:
        return Response.fail(
            code=ResponseCode.FORBIDDEN,
            message="无权操作此任务"
        )
    
    # 检查任务状态
    if task.status not in ["pending", "failed"]:
        return Response.fail(
            code=ResponseCode.BAD_REQUEST,
            message=f"当前任务状态为 {task.status}，无法启动"
        )
    
    # 开始任务
    updated_task = start_detection(db, task_id)
    
    return Response.success(data=updated_task, message="任务已启动")


@router.get("/tasks/{task_id}/statistics", response_model=Response[TaskStatistics])
def read_task_statistics(
    task_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """获取任务统计数据
    
    Args:
        task_id: 任务ID
        
    Returns:
        Response[TaskStatistics]: 任务统计数据
    """
    # 检查任务是否存在
    task = get_task(db, task_id)
    if not task:
        return Response.fail(
            code=ResponseCode.NOT_FOUND,
            message="任务不存在"
        )
    
    # 检查是否为当前用户的任务
    if task.user_id != current_user.id:
        return Response.fail(
            code=ResponseCode.FORBIDDEN,
            message="无权访问此任务"
        )
    
    # 检查任务状态
    if task.status != "completed":
        return Response.fail(
            code=ResponseCode.BAD_REQUEST,
            message="任务尚未完成，无法获取统计数据"
        )
    
    # 获取统计数据
    statistics = get_task_statistics(db, task_id)
    
    return Response.success(data=statistics, message="获取统计数据成功")


@router.get("/models", response_model=Response[List[dict]])
def read_available_models(
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """获取所有可用的已训练模型
    
    Returns:
        Response[List[dict]]: 模型列表
    """
    models = get_available_models()
    return Response.success(data=models, message="获取模型列表成功")


@router.post("/run_model", response_model=Response[dict])
def run_model_prediction(
    model_type: str = Form(...),  # "CNN", "LSTM", "CNN+LSTM"
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """使用选定的模型进行入侵检测
    
    Args:
        model_type: 模型类型
        file: 上传的数据集文件
        
    Returns:
        Response: 包含检测结果的响应
    """
    try:
        # 保存上传文件
        filepath = save_uploaded_file(file, UPLOAD_DIR)
        
        # 执行预测
        results = run_prediction(model_type, filepath)
        
        # 保存到数据库
        log_id = save_prediction_to_db(results, current_user.id, db)
        
        # 添加日志ID到返回结果
        results["log_id"] = log_id
        
        return Response.success(data=results, message="检测完成")
    except Exception as e:
        return Response.error(message=f"预测失败: {str(e)}")


@router.get("/latest_result", response_model=Response[dict])
def read_latest_prediction(
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """获取最新的预测结果
    
    Returns:
        Response: 包含最新预测结果的响应
    """
    result = get_latest_prediction_result()
    if result:
        return Response.success(data=result, message="获取最新预测结果成功")
    return Response.fail(message="没有找到预测结果")


@router.get("/prediction_logs", response_model=Response[dict])
def read_prediction_logs(
    skip: int = 0,
    limit: int = 20,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """获取用户的预测日志列表
    
    Args:
        skip: 跳过记录数
        limit: 返回记录数
        
    Returns:
        Response: 包含预测日志列表和分页信息的响应
    """
    # 查询总记录数
    total = db.query(PredictionLog).filter(
        PredictionLog.user_id == current_user.id
    ).count()
    
    # 获取分页数据
    logs = db.query(PredictionLog).filter(
        PredictionLog.user_id == current_user.id
    ).order_by(
        PredictionLog.created_at.desc()
    ).offset(skip).limit(limit).all()
    
    logs_data = []
    for log in logs:
        logs_data.append({
        "id": log.id,
        "model_type": log.model_type,
        "dataset_name": log.dataset_name,
        "dataset_path": log.dataset_path,
        "accuracy": log.accuracy,
        "precision_score": log.precision_score,
        "recall_score": log.recall_score,
        "f1_score": log.f1_score,
        "loss": log.loss,
        "sample_count": log.sample_count,
        "feature_count": log.feature_count,
        "class_count": log.class_count,
        "class_distribution": json.loads(log.class_distribution) if log.class_distribution else {},
        "prediction_time": log.prediction_time,
        "created_at": log.created_at.strftime("%Y-%m-%d %H:%M:%S")
        })
    
    # 构建分页元数据
    pagination = {
        "total": total,
        "skip": skip,
        "limit": limit,
        "has_more": total > (skip + limit)
    }
    
    return Response.success(
        data={
            "items": logs_data,
            "pagination": pagination
        },
        message="获取预测日志列表成功"
    )


@router.get("/prediction_logs/{log_id}", response_model=Response[dict])
def read_prediction_log(
    log_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """获取单个预测日志详情
    
    Args:
        log_id: 日志ID
        
    Returns:
        Response: 包含预测日志详情的响应
    """
    log = db.query(PredictionLog).filter(
        PredictionLog.id == log_id,
        PredictionLog.user_id == current_user.id
    ).first()
    
    if not log:
        return Response.fail(message="预测日志不存在或无权访问")
    
    # 尝试加载完整的JSON结果文件
    result_file = log.result_file_path
    full_result = None
    if result_file and os.path.exists(result_file):
        try:
            with open(result_file, 'r') as f:
                full_result = json.load(f)
        except:
            pass
    
    log_data = {
        "id": log.id,
        "model_type": log.model_type,
        "dataset_name": log.dataset_name,
        "dataset_path": log.dataset_path,
        "accuracy": log.accuracy,
        "precision_score": log.precision_score,
        "recall_score": log.recall_score,
        "f1_score": log.f1_score,
        "loss": log.loss,
        "sample_count": log.sample_count,
        "feature_count": log.feature_count,
        "class_count": log.class_count,
        "class_distribution": json.loads(log.class_distribution) if log.class_distribution else {},
        "prediction_time": log.prediction_time,
        "created_at": log.created_at.strftime("%Y-%m-%d %H:%M:%S"),
        "full_result": full_result
    }
    
    return Response.success(data=log_data, message="获取预测日志详情成功")